﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Menafrinet.Core;

namespace Menafrinet.ViewModel
{
    /// <summary>
    /// Class representing the view model for a case.
    /// </summary>
    public class CaseViewModel : ObservableObject
    {
        #region Members
        /// <summary>
        /// Represents the case model
        /// </summary>
        private Case mCase;

        /// <summary>
        /// Whether to flag this case as a duplicate of another case (in this case by EPID)
        /// </summary>
        private bool _flagAsDuplicate = false;

        /// <summary>
        /// Represents whether the EPID for this case is invalid
        /// </summary>
        private bool _flagEPIDAsInvalid = false;
        #endregion

        #region Properties
        /// <summary>
        /// Gets/sets whether to flag this case as being a duplicate (the detection of duplicates should occur based on EPID values)
        /// </summary>
        public bool FlagAsDuplicate
        {
            get { return _flagAsDuplicate; }
            set
            {
                if (_flagAsDuplicate != value)
                {
                    _flagAsDuplicate = value;
                    RaisePropertyChanged("FlagAsDuplicate");
                }
            }
        }

        /// <summary>
        /// Gets/sets whether to flag this case's EPID as being invalid
        /// </summary>
        public bool FlagEPIDAsInvalid
        {
            get { return _flagEPIDAsInvalid; }
            set
            {
                if (_flagEPIDAsInvalid != value)
                {
                    _flagEPIDAsInvalid = value;
                    RaisePropertyChanged("FlagEPIDAsInvalid");
                }
            }
        }

        /// <summary>
        /// The Epi Info-generated record status for this record
        /// </summary>
        public byte RecStatus
        {
            get { return Case.RecStatus; }
            set
            {
                if (Case.RecStatus != value)
                {
                    Case.RecStatus = value;
                    RaisePropertyChanged("RecStatus");
                }
            }
        }

        /// <summary>
        /// The Epi Info-generated GUID for this record
        /// </summary>
        public string Guid
        {
            get { return Case.Guid; }
            set
            {
                if (Case.Guid != value)
                {
                    Case.Guid = value;
                    RaisePropertyChanged("Guid");
                }
            }
        }
        /// <summary>
        /// The Epi Info unique key for this record
        /// </summary>
        public int UniqueKey
        {
            get { return Case.UniqueKey; }
            set
            {
                if (Case.UniqueKey != value)
                {
                    Case.UniqueKey = value;
                    RaisePropertyChanged("UniqueKey");
                }
            }
        }

        public Case Case
        {
            get
            {
                return this.mCase;
            }
            set
            {
                this.mCase = value;

                #region EPID validation
                this.FlagEPIDAsInvalid = false;

                // Check #1 - Is it empty?
                if (String.IsNullOrEmpty(Case.EPID.Trim()))
                {
                    this.FlagEPIDAsInvalid = true;
                }
                // Check #2 - Is it the correct length?
                if (Case.EPID.Length != 23)
                {
                    this.FlagEPIDAsInvalid = true;
                }
                // Check #3 - Are all dash positions correct?
                else if (Case.EPID[3] != '-' || Case.EPID[7] != '-' || Case.EPID[11] != '-' || Case.EPID[14] != '-' || Case.EPID[18] != '-')
                {
                    this.FlagEPIDAsInvalid = true;
                }

                #endregion // EPID validation
            }
        }

        /// <summary>
        /// The EPID for this record
        /// </summary>
        public string EPID
        {
            get { return Case.EPID; }
            set
            {
                if (Case.EPID != value)
                {
                    Case.EPID = value;
                    RaisePropertyChanged("EPID");

                    #region EPID validation
                    this.FlagEPIDAsInvalid = false;

                    // Check #1 - Is it empty?
                    if(String.IsNullOrEmpty(Case.EPID.Trim())) 
                    {
                        this.FlagEPIDAsInvalid = true;
                    }
                    // Check #2 - Is it the correct length?
                    if (Case.EPID.Length != 23)
                    {
                        this.FlagEPIDAsInvalid = true;
                    }
                    // Check #3 - Are all dash positions correct?
                    else if (Case.EPID[3] != '-' || Case.EPID[7] != '-' || Case.EPID[11] != '-' || Case.EPID[14] != '-' || Case.EPID[18] != '-')
                    {
                        this.FlagEPIDAsInvalid = true;
                    }

                    #endregion // EPID validation
                }
            }
        }
        /// <summary>
        /// The case's first name
        /// </summary>
        public string FirstName
        {
            get { return Case.FirstName; }
            set
            {
                if (Case.FirstName != value)
                {
                    Case.FirstName = value;
                    RaisePropertyChanged("FirstName");
                }
            }
        }
        /// <summary>
        /// The case's last name
        /// </summary>
        public string LastName
        {
            get { return Case.LastName; }
            set
            {
                if (Case.LastName != value)
                {
                    Case.LastName = value;
                    RaisePropertyChanged("LastName");
                }
            }
        }
        /// <summary>
        /// The name of the case's parent (if the case is a child)
        /// </summary>
        public string NameOfParent
        {
            get { return Case.NameOfParent; }
            set
            {
                if (Case.NameOfParent != value)
                {
                    Case.NameOfParent = value;
                    RaisePropertyChanged("NameOfParent");
                }
            }
        }
        /// <summary>
        /// The sex of the case
        /// </summary>
        public string Sex
        {
            get { return Case.Sex; }
            set
            {
                if (Case.Sex != value)
                {
                    Case.Sex = value;
                    RaisePropertyChanged("Sex");
                }
            }
        }
        /// <summary>
        /// The case's classification (e.g. confirmed, probable, suspect)
        /// </summary>
        public string Classification
        {
            get { return Case.Classification; }
            set
            {
                if (Case.Classification != value)
                {
                    Case.Classification = value;
                    RaisePropertyChanged("Classification");
                }
            }
        }
        /// <summary>
        /// The age of the case measured in years
        /// </summary>
        public int? EpiWeek
        {
            get { return Case.EpiWeek; }
            set
            {
                if (Case.EpiWeek != value)
                {
                    Case.EpiWeek = value;
                    RaisePropertyChanged("EpiWeek");
                }
            }
        }
        /// <summary>
        /// The year
        /// </summary>
        public double? Year
        {
            get { return Case.Year; }
            set
            {
                if (Case.Year != value)
                {
                    Case.Year = value;
                    RaisePropertyChanged("Year");
                }
            }
        }
        /// <summary>
        /// The age of the case measured in years
        /// </summary>
        public double? Age
        {
            get { return Case.Age; }
            set
            {
                if (Case.Age != value)
                {
                    Case.Age = value;
                    RaisePropertyChanged("Age");
                }
            }
        }
        /// <summary>
        /// The age of the case measured in WHOLE years
        /// </summary>
        public double? AgeYears
        {
            get { return Case.AgeYears; }
            set
            {
                if (Case.AgeYears != value)
                {
                    Case.AgeYears = value;
                    RaisePropertyChanged("AgeYears");
                }
            }
        }
        /// <summary>
        /// The age of the case measured in WHOLE months
        /// </summary>
        public double? AgeMonths
        {
            get { return Case.AgeMonths; }
            set
            {
                if (Case.AgeMonths != value)
                {
                    Case.AgeMonths = value;
                    RaisePropertyChanged("AgeMonths");
                }
            }
        }        
        /// <summary>
        /// Whether the case is urban or rural
        /// </summary>
        public string UrbanRural
        {
            get { return Case.UrbanRural; }
            set
            {
                if (Case.UrbanRural != value)
                {
                    Case.UrbanRural = value;
                    RaisePropertyChanged("UrbanRural");
                }
            }
        }
        /// <summary>
        /// The case's district of residence
        /// </summary>
        public string DistrictResidence
        {
            get { return Case.DistrictResidence; }
            set
            {
                if (Case.DistrictResidence != value)
                {
                    Case.DistrictResidence = value;
                    RaisePropertyChanged("DistrictResidence");
                }
            }
        }
        /// <summary>
        /// The case's district of reporting
        /// </summary>
        public string DistrictReporting
        {
            get { return Case.DistrictReporting; }
            set
            {
                if (Case.DistrictReporting != value)
                {
                    Case.DistrictReporting = value;
                    RaisePropertyChanged("DistrictReporting");
                }
            }
        }
        /// <summary>
        /// The case's city
        /// </summary>
        public string City
        {
            get { return Case.City; }
            set
            {
                if (Case.City != value)
                {
                    Case.City = value;
                    RaisePropertyChanged("City");
                }
            }
        }
        /// <summary>
        /// The date of birth for the case
        /// </summary>
        public DateTime? DOB
        {
            get { return Case.DOB; }
            set
            {
                if (Case.DOB != value)
                {
                    Case.DOB = value;
                    RaisePropertyChanged("DOB");
                }
            }
        }
        /// <summary>
        /// Case's health facility
        /// </summary>
        public string HealthFacility
        {
            get { return Case.HealthFacility; }
            set
            {
                if (Case.HealthFacility != value)
                {
                    Case.HealthFacility = value;
                    RaisePropertyChanged("HealthFacility");
                }
            }
        }
        /// <summary>
        /// Date of onset of illness for the case
        /// </summary>
        public DateTime? DateOnset
        {
            get { return Case.DateOnset; }
            set
            {
                if (Case.DateOnset != value)
                {
                    Case.DateOnset = value;
                    RaisePropertyChanged("DateOnset");
                }
            }
        }

        /// <summary>
        /// Final lab class for the case
        /// </summary>
        public string FinalLabResult
        {
            get { return Case.FinalLabResult; }
            set
            {
                if (Case.FinalLabResult != value)
                {
                    Case.FinalLabResult = value;
                    RaisePropertyChanged("FinalLabResult");
                }
            }
        }

        public string LPPerformed
        {
            get { return Case.LPPerformed; }
            set
            {
                if (Case.LPPerformed != value)
                {
                    Case.LPPerformed = value;
                    RaisePropertyChanged("LPPerformed");
                }
            }
        }

        /// <summary>
        /// Outcome for the case
        /// </summary>
        public string Outcome
        {
            get { return Case.Outcome; }
            set
            {
                if (Case.Outcome != value)
                {
                    Case.Outcome = value;
                    RaisePropertyChanged("Outcome");
                }
            }
        }

        /// <summary>
        /// Created date
        /// </summary>
        public DateTime? DateRecordCreated
        {
            get { return Case.DateRecordCreated; }
            set
            {
                if (Case.DateRecordCreated != value)
                {
                    Case.DateRecordCreated = value;
                    RaisePropertyChanged("DateRecordCreated");
                }
            }
        }

        /// <summary>
        /// Last updated date
        /// </summary>
        public DateTime? DateRecordUpdated
        {
            get { return Case.DateRecordUpdated; }
            set
            {
                if (Case.DateRecordUpdated != value)
                {
                    Case.DateRecordUpdated = value;
                    RaisePropertyChanged("DateRecordUpdated");
                }
            }
        }
        #endregion // Properties

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        public CaseViewModel()
        {
            Case = new Case();
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="newCase">The case model to copy from</param>
        public CaseViewModel(Case newCase)
        {
            Case = new Case();
            UpdateCase(newCase);
        }
        #endregion // Constructors

        #region Methods
        /// <summary>
        /// Updates this case view model with data from a case model
        /// </summary>
        /// <param name="updatedCase">The case model that should update this case view model</param>
        public void UpdateCase(Case updatedCase)
        {
            this.Guid = updatedCase.Guid;
            this.UniqueKey = updatedCase.UniqueKey;
            this.EPID = updatedCase.EPID;
            this.FirstName = updatedCase.FirstName;
            this.LastName = updatedCase.LastName;
            this.NameOfParent = updatedCase.NameOfParent;
            this.Sex = updatedCase.Sex;
            this.Classification = updatedCase.Classification;
            this.EpiWeek = updatedCase.EpiWeek;
            this.Age = updatedCase.Age;
            this.AgeYears = updatedCase.AgeYears;
            this.AgeMonths = updatedCase.AgeMonths;
            this.UrbanRural = updatedCase.UrbanRural;
            this.DistrictResidence = updatedCase.DistrictResidence;
            this.DistrictReporting = updatedCase.DistrictReporting;
            this.City = updatedCase.City;
            this.DOB = updatedCase.DOB;
            this.HealthFacility = updatedCase.HealthFacility;
            this.DateOnset = updatedCase.DateOnset;
            this.RecStatus = updatedCase.RecStatus;
            this.FinalLabResult = updatedCase.FinalLabResult;
            this.Outcome = updatedCase.Outcome;

            this.DateRecordCreated = updatedCase.DateRecordCreated;
            this.DateRecordUpdated = updatedCase.DateRecordUpdated;
        }
        #endregion // Methods

        #region Commands
        void UpdateExecute(Case updatedCase)
        {
            UpdateCase(updatedCase);
        }

        public ICommand Update { get { return new RelayCommand<Case>(UpdateExecute); } }
        #endregion
    }
}
